#include "Hierarchy.h"
#include<imgui\imgui.h>
#include<omp.h>
#include<string>
#include"Event.h"
using namespace ECS;
using namespace SYSTEM;
using namespace Component;

struct Hierarchy::Impl
{
	Entity* selectedId = nullptr;
	Entity* hoverID = nullptr;
	bool selectedChange = false;

	// ban moving to it`s children
	bool HierarchyMovable( Entity* dst,const Entity* src)
	{
		if (dst == src)
			return false;
		else if (const auto p = dst->get<SceneGraphComp>()->Parent)
			return HierarchyMovable(p, src);

		return true;
	}
	void PrintEntityRecursive(Entity* e)
	{
		auto& sg = e->get<SceneGraphComp>();
		auto& children = sg->Children;
		auto currentId = e->getEntityId();
		bool isLeaf = children.empty();

		ImGuiTreeNodeFlags nodeFlags = 0;
		if (isLeaf)
			nodeFlags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen;
		if (selectedId == e)
			nodeFlags |= ImGuiTreeNodeFlags_Selected;

		bool nodeOpen = ImGui::TreeNodeEx(
			(void*)(intptr_t)currentId,
			nodeFlags,"%s (%d)", sg->name.c_str(), currentId);

		if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) {
			ImGui::SetDragDropPayload(YXX::PayloadType::ENTITY, e, sizeof(ECS::Entity));
			
			ImGui::Text("Entity (%d)", currentId);

			ImGui::EndDragDropSource();
		}

		if (ImGui::BeginDragDropTarget()) {
			if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(YXX::PayloadType::ENTITY)) {
				IM_ASSERT(payload->DataSize == sizeof(ECS::Entity));
				auto payload_e = (ECS::Entity*)(payload->Data);
				auto realpayload_e = e->getWorld()->getById(payload_e->getEntityId());

				auto& payload_sg = realpayload_e->get<SceneGraphComp>();
				if (HierarchyMovable(e, realpayload_e))
				{
					// delete it in his old parent
					Entity* parent;
					if (parent = payload_sg->Parent)
					{
						parent->get<SceneGraphComp>()->Children.erase(realpayload_e);
					}
					// add it to his new parent;
					e->get<SceneGraphComp>()->Children.insert(realpayload_e);
					payload_sg->Parent = e;
				}
			}
			ImGui::EndDragDropTarget();
		}

		if (ImGui::IsItemDeactivated())
		{
			selectedId = e;
			selectedChange = true;
		}

		if (ImGui::IsItemHovered())
			hoverID = e;

		if (nodeOpen && !isLeaf)
		{
			for (auto child : children)
				PrintEntityRecursive(child);
			
			ImGui::TreePop();
		}
	}

	void DeleteEntityRecursive(Entity* e)
	{
		auto world = e->getWorld();

		for (auto child : e->get<Component::SceneGraphComp>()->Children)
		{
			DeleteEntityRecursive(child);
		}

		world->destroy(e,true);
	}

	void DealManageOperator(World* world)
	{
		if (ImGui::IsWindowHovered() && ImGui::IsMouseClicked(ImGuiMouseButton_Right))
			ImGui::OpenPopup("Hierarchy_Popup");

		if (ImGui::BeginPopup("Hierarchy_Popup"))
		{
			
			
			if (hoverID)
			{
				if (ImGui::MenuItem("Create Entity"))
				{
					auto child = Component::CreateNewEntity(world);
					child->get<Component::SceneGraphComp>()->Parent = hoverID;
					hoverID->get<Component::SceneGraphComp>()
						->Children.insert(child);

				}
				if (ImGui::MenuItem("Delete"))
				{
					// delete from parent
					
					if (auto p = hoverID->get<Component::SceneGraphComp>()->Parent)
					{
						p->get<Component::SceneGraphComp>()->Children.erase(hoverID);
					}					

					// delete itself and children
					DeleteEntityRecursive(hoverID);


					selectedId = nullptr;
					selectedChange = true;
					hoverID = nullptr;
				}
			}
			else
			{
				if (ImGui::MenuItem("Create Empty Entity"))
					Component::CreateNewEntity(world);
			}
			ImGui::EndPopup();
		}
		else
			hoverID = nullptr;
	}

	void DealModifyOperator(World* world)
	{
		if (ImGui::BeginDragDropTarget())
		{
			if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(YXX::PayloadType::ENTITY)) {
				IM_ASSERT(payload->DataSize == sizeof(ECS::Entity));
				auto payload_e = (ECS::Entity*)(payload->Data);
				auto realpayload_e = world->getById(payload_e->getEntityId());

				auto& payload_sg = realpayload_e->get<SceneGraphComp>();
				// delete it in his old parent
				if(Entity* parent = payload_sg->Parent)
					parent->get<SceneGraphComp>()->Children.erase(realpayload_e);
				

				// add it to root;
				payload_sg->Parent = nullptr;
			}
			ImGui::EndDragDropTarget();
		}
	}
};
SYSTEM::Hierarchy::Hierarchy()
{
	mpImpl = std::make_unique<Hierarchy::Impl>();
}
void SYSTEM::Hierarchy::tick(ECS::World* world, float deltaTime)
{
	ImGui::Begin("Hierarchy");
	
	// deal with create and delete
	mpImpl->DealManageOperator(world);

	// deal with change parent to root
	mpImpl->DealModifyOperator(world);

	world->each<Component::SceneGraphComp>(
		[&](Entity* e, ComponentHandle<SceneGraphComp>& sgComp) {
			// top element
			if (sgComp->Parent == nullptr)
				mpImpl->PrintEntityRecursive(e);

		});
	
	ImGui::End();

	if (mpImpl->selectedChange)
	{
		mpImpl->selectedChange = false;
		world->emit<EVENT::EditorSelected>(EVENT::EditorSelected{mpImpl->selectedId});
	}
}


